1 ESBOÇO FLUXO DE TRABALHO DO PRODUTO 2 - CÓDIGOS

1.1 PARTE I – Cuidados antes de começar a rodar os códigos no R

Pensar quais orientações são mais gerais e quais são importantes de acompanhar cada código.

1.1.1 Rstudio/Pacotes/versões/sistemas operacionais

Sobre os pacotes, seria bom ter uma listinha de ‘library’ no início de cada código? Talvez com uma breve explicação do que cada pacote faz, versão mínima… não sei.

OBS: essa tabela é uma referência para obtermos as versões dos pacotes ao final do desenvolvimento do script. Ela está automatizada, então quando terminarmos ele precisamos refaze-lo de forma que não gere mais mudança nas versões (tem que fazer a tabela na mão mesmo…).

# carregar pacote para formatar tabela
library(flextable)

# gerar informações sobre os pacotes carregados
info <- sessionInfo()

# gerar tabela com os pacotes e versões
tibble::tribble(
  ~Pacotes,                         ~Versão,
  version$language,                 version$version.string,
  info$otherPkgs$dplyr$Package,     info$otherPkgs$dplyr$Version,
  info$otherPkgs$Distance$Package,  info$otherPkgs$Distance$Version,
  info$otherPkgs$DT$Package,        info$otherPkgs$DT$Version,
  info$otherPkgs$flextable$Package, info$otherPkgs$flextable$Version,
  info$otherPkgs$plotly$Package,    info$otherPkgs$plotly$Version,
  info$otherPkgs$readr$Package,     info$otherPkgs$readr$Version,
  info$otherPkgs$tibble$Package,    info$otherPkgs$tibble$Version,
  info$otherPkgs$tidyr$Package,     info$otherPkgs$tidyr$Version,
) |> 
  qflextable() |> 
  set_caption(
    "Tabela xx - configuração de pacotes necessários e respectivas versões mínimas que devem ser utilizadas para reproduzir os códigos"
  )
Tabela xx - configuração de pacotes necessários e respectivas versões mínimas que devem ser utilizadas para reproduzir os códigos

Pacotes

Versão

[[character]]

[[character]]

[[character]]

[[character]]

[[NULL]]

[[NULL]]

[[character]]

[[character]]

[[character]]

[[character]]

[[NULL]]

[[NULL]]

[[character]]

[[character]]

[[NULL]]

[[NULL]]

[[character]]

[[character]]

1.1.2 Cuidados com a planilha .xlsx que será importada (para que mantenha o padrão da planilha de referência do ICMBio)

Algumas funções foram escritas para funcionar tomando como base de dados de referência a planilha em formato excel Planilha Oficial consolidada de Masto-aves 2014-21 Validada CEMAVE CPB CENAP.xlsx disponibilizada pelo Projeto Monitora. Estas funções carregam os dados e fazem uma série de transformações para devolve-los no formato padronizado do programa DISTANCE para Windows. Portanto, para garantir a reprodutibilidade dos códigos produzidos em versões atualizadas da base de dados do Monitora, é importante tomar alguns cuidados.

O primeiro e mais importante cuidado é manter os mesmos nomes das colunas em versões atualizadas da base de dados do Monitora. As primeiras funções, além de carregar os dados, aplicam uma série de transformações. Os nomes das colunas são alterados, e a essas são atribuídos tipos (data, caracter, fator , inteiro e numérico), linhas são eliminadas e novas colunas são gereadas. Para exemplificar, veja o código abaixo. Ele foi escrito para executar as primeiras transformações nos dados e constitui o corpo da função carregar_dados_filtrados().

# carregar pacotes para manipulação dos dados
library(tidyr)
library(dplyr)
library(readxl)

# carregar função corrigir_diretorio
source(
  paste0(
    stringr::str_remove(
      getwd(), 
      'doc'
    ),
    "R/corrigir_diretorio.R"
  )
) 

# carregar a base de dados do Monitora
dados_brutos <- read_excel(
  path = corrigir_diretorio(
    corrige = "/data-raw/Planilha Oficial consolidada de Masto-aves 2014-21 Validada CEMAVE CPB CENAP.xlsx"
  ),
  sheet = "dados brutos"
)

# gerar o data.frame desejado
dados_completos <- dados_brutos |>  
  # selecionar as colunas necessárias para as analises, padronizando os nomes para o formato DISTANCE
  dplyr::select(
    uc_code = CDUC,
    uc_name = `Local - Nome da Unidade de Conservação`,
    ea_number = `Número da Estação Amostral`,
    ea_name = `Nome da EA`,
    season = `Estação do ano`,
    sampling_day = `data da amostragem`,
    day_effort = `Esforço de amostragem tamanho da trilha (m)`,
    sp = `Espécies validadas para análise do ICMBio`,
    distance = `distância (m)     do animal em relação a trilha`,
    group_size = `n° de animais`,
    observadores = `nome dos observadores`
  ) |>
  # atribuir os tipos corretos às colunas e criar novas colunas
    dplyr::mutate(
      uc_category = stringi::stri_extract_first_words(
      uc_name
    ),
    # abrevia o nome das UCs
    uc_name_abv = forcats::lvls_revalue(
      uc_name,
      new_levels = c(
        "ETM", "EM", "EN", "ESGT", "FJ", "PCV", "PA", "PSBoc", "PSBod", "PSC",
        "PSM", "PSC", "PSD", "PSP", "PSO", "PPN", "PCO", "PI", "PJaú", "PJur",
        "PMR", "PS", "PV", "PCA", "PMT", "RG", "RJ", "RTap", "RU", "RG",
        "RTrom", "RAT", "RBA", "RCI", "RCM", "RRC", "RROP", "RIA", "RRA", "RTA"
      )
    ),
      # atribuir o tipo data à coluna sampling_day
      year = lubridate::year(
        sampling_day
      ),
      # atribuir o tipo fator às colunas do tipo caracter
      across(
        where(
          is.character
        ),
        as.factor
      ),
      # substituir separadores de nome por ","
      novo = stringr::str_replace_all(
        observadores, 
        " e ",
        ", "
      ),
      # substituir separadores de nome por ","
      novo = stringr::str_replace_all(
        novo, 
        " E ",
        ", "
      ),
      # substituir separadores de nome por ","
      novo = stringr::str_replace_all(
        novo, 
        "/",
        ", "
      ),
      # substituir separadores de nome por ","
      novo = stringr::str_replace_all(
        novo, 
        ";",
        ", "
      ),
      # substituir separadores de nome por ","
      novo = stringr::str_replace_all(
        novo, 
        " a ",
        ", "
      ) 
    ) |>
  # transformar os nomes dos observadores da coluna novo em colunas individuais
tidyr::separate_wider_delim(
  novo, 
  ",",
  names = c(
    "obs1", "obs2", "obs3", "obs4", "obs5", "obs6"
  ),
  too_few = "align_start"
) |> 
  # gerar uma nova coluna number_observers com o número total de observadores em um mesmo transecto
  dplyr::mutate(
    # se o valor da observação é diferente de NA, substituir por 1, se for NA, substituir por 0
    obs1 = ifelse(!is.na(obs1), 1, 0),
    obs2 = ifelse(!is.na(obs2), 1, 0),
    obs3 = ifelse(!is.na(obs3), 1, 0),
    obs4 = ifelse(!is.na(obs4), 1, 0),
    obs5 = ifelse(!is.na(obs5), 1, 0),
    obs6 = ifelse(!is.na(obs6), 1, 0),
    # gera nova coluna number_observers a partir da soma das colunas de observadores individuais
    number_observers = obs1 + obs2 + obs3 + obs4 + obs5 + obs6
  ) |> 
  # agrupar os dados pelas colunas ea_name e sampling_day
  group_by(
    ea_name, 
    sampling_day
  ) |> 
  # aninhar as observações agrupadas uem listas
  nest() |> 
  # completar com o valor correto as linhas vazias das da variável day_effort
  mutate(
    day_effort2 = purrr::map(
      data, \(.x) rep(
        .x$day_effort[
          !is.na(
            .x$day_effort
          )
        ][1]
      )
    )
  ) |> 
  # desanihar os dados
  unnest(
    c(
      data, 
      day_effort2
    )
  ) |> 
  # desagrupar os dados
  ungroup() |> 
  # selecionar as colunas desejadas e excluir as indesejadas
  select(
    tidyselect::starts_with(c("uc", "ea")),
    season,
    year,
    sampling_day,
    day_effort = day_effort2,
    sp:number_observers,
    -day_effort,
    -tidyselect::starts_with("obs")
  ) |>
  # filtrar os dados pela UC e espécie desejadas
    dplyr::filter(
      uc_name == "Resex Tapajós-Arapiuns",
      sp == "Dasyprocta croconota"
    ) |> 
  relocate(
    uc_category,
    .before = uc_name
  ) |> 
  relocate(
    uc_name_abv,
    .after = uc_name
  )

# gerar tabela dinâmica dos dados brutos
dados_completos |> 
  slice(1:100) |> 
  DT::datatable(filter = list(position = "top"))

O trecho do código que vai da linha 101 a 113 serve selecionar apenas as colunas de interesse presente nos dados originais. Note que os nomes das planilhas originais constam nesse trecho. Caso o nome de qualque uma dessas colunas seja alterado a função deixará de funcionar.

Outro aspecto importante é a presença de observações não preenchidas (ex. células vazias) nos dados originais. A função foi desenha para resolver alguns problemas presentes nos dados originais. Por exemplo, nas o trecho do código das linhas xx a xx as observações vazias (NAs) são substituidas pelo valor correto na coluna day_effort. Essa correção continnuará sendo realizada em versões atualizadas dos dados do Monitora. Porém, se outras colunas além das que estão sendo corrigidas possuirem observações vazias os dados serão carregados e transformados, porém outras funções podem ter o seu funcionamento comprometido. Por exemplo… (funções de visualização e do pacote distance que podem naõ funcionar devido a ausência de observação)

Outros cuidados…

Imaginando que a planilha de dados do monitora é algo dinâmico, que o nome das colunas pode ser editado…

1.1.3 Como abrir os arquivos: como salvar e descompactar a pasta. Abrir projeto

Um passo a passo de como salvar arquivo com os códigos e abrir.. Por exemplo, da forma como está é interessante descompactar a pasta e acessar os arquivos abrindo o projeto. Acho que isso pode mudar, dependendo de como viermos a entregar o produto final. Então podemos pensar nessa explicação no final.

1.1.4 Cuidados com diretório

Se a gente ainda precisar ter algum tipo de preocupação quanto a isso. Acho que não.

1.1.5 Como rodar cada tipo de arquivo (markdown, shiny)

Não é trivial para quem não está acostumado… usar runApp, knit… até mesmo o shift+enter para rodar as linhas de comando uma a uma

1.2 PARTE II – Carregando os dados para o R

1.2.1 Dados brutos

  • todas espécies/UCs – carrega_dados_1.Rmd
# carregar pacote
library(DT)

# carregar a função
source(
  corrigir_diretorio(
  corrige = 'R/carregar_dados_completos.R'
  )
)

# carregar dados para o R
dados_completos <- carregar_dados_completos() 


dados_completos |> 
  slice(1:500) |> 
  datatable(
    filter = list(
      position = "top"
    )
  )

1.2.2 Dados filtrados

  • por espécie/UC – carrega_dados_2.Rmd até o momento usado com o exemplo da cutia na Resex Tapajós-Arapiuns
# carregar a função
source(
  corrigir_diretorio(
     corrige = 'R/carregar_dados_filtrados.R'
  )
  )

# carregar dados para o R
dados_filtrados <- carregar_dados_filtrados(
  dados = corrigir_diretorio(
    corrige =  'data-raw/dados-brutos.xlsx'
  ),
  nome_uc = "Resex Tapajós-Arapiuns",
  nome_sp = "Dasyprocta croconota"
)

dados_filtrados |> 
  datatable(
    filter = list(
      position = "top"
    )
  )

1.3 Parte III – Transformando dados para Distance

1.3.1 Dados completos

  • todas espécies/UCs – transforma_para_distanceR.Rmd
# carregar as funções
source(
  corrigir_diretorio(
    corrige = "R/carregar_dados_completos.R"
  )
  ) 

source(
  corrigir_diretorio(
    corrige = "R/transforma_para_distanceR.R"
  )
)

# carregar dados para o R
dados_completos <- carregar_dados_completos()

# transformar os dados para o formato do Distance
dados_distanceR_completo <- transforma_para_distanceR(
  dados_completos
)

dados_distanceR_completo |> 
  slice(1:500) |> 
  datatable(
    filter = list(
      position = "top"
    )
  )
# carregar as funções
source(
  corrigir_diretorio(
  corrige = "R/transforma_para_distanceR_covariaveis.R"
)
)

# carregar dados para o R
dados_filtrados <- read_rds(
  file = corrigir_diretorio(
    corrige = "data/dados_filtrados.rds"
  )
  )

# transformar os dados para o formato do Distance
dados_distanceR_covariaveis <- transforma_para_distanceR_covariaveis(
  dados = dados_filtrados
)

dados_distanceR_covariaveis |> 
  slice(1:500) |> 
  datatable(
    filter = list(
      position = "top"
    )
  )

1.3.2 Dados selecionados

Sistematizar os critérios utilizados para eliminar observações (linhas).

  • espécies validadas

1.4 Quantas observações foram validadas para quais níveis taxonômicos?

n_sp_validada <- dados_completos |> 
  count(validation)

Foram selecionadas apenas as observações validadas ao nível de espécie, somando um total 20790 observações.

# carregar as funções
source(
  corrigir_diretorio(
    corrige = "R/carregar_dados_completos.R"
  )
  ) 
source(
  corrigir_diretorio(
    corrige = "R/grafico_n_sp_validadas.R"
  )
)

# carregar dados para o R
dados_completos <- carregar_dados_completos()

# gerar gráfico com número observações validadas para cada nível taxonômico
grafico_n_sp_validadas()

# carregar função carregar dados selecionados
source(
  corrigir_diretorio(
    corrige = "R/carregar_dados_selecionados.R"
  )
)

# gerar tabela de dados selecionados
dados_selecionados <- carregar_dados_selecionados()

dados_selecionados |> 
  slice(1:500) |> 
  datatable(
    filter = list(
      position = "top"
    )
  )

1.4.1 PARTE IV – Explorando os dados

1.4.2 Selecionando os melhores modelos de estudo de acordo com os dados

Critŕios:

  • espécies com maior volume de dados total
  • maior volume de dados por UC – exploração_01.nb.html (acho que o .Rmd para gerar esse html não está na pasta Monitora). Eu tinha gostado bastante desse documento, com as tabelas dinâmicas. Talvez dê para selecionar as perguntas que são válidas de deixar/ tirar/ incluir.

WWF - Projeto Monitora

1.4.2.1 Exploração de dados

1.4.2.2 Informações básicas

1.4.2.3 Quantas unidades de conservação ao todo?

source(
  corrigir_diretorio(
    corrige = "R/contar_UCs.R"
  )
)

n_ucs <- contar_UCs(
  dados_selecionados
)

Os dados são provenientes de 40 unidades de conservação ao todo.

1.4.2.4 Quantas espécies ao todo?

source(
  corrigir_diretorio(
    corrige = "R/contar_sp.R"
  )
)

n_sp <- contar_sp(
  dados_completos
)

Foram coletados dados para 209 espécies.

1.4.2.5 Quantas observações por unidade de conservação ao todo?

As UC’s foram filtradas de acordo com o número de observações permitir a visualização.

A função de contagem de UC’s gerou 40 UC’s, mas só há observações para 38. Lembrar de verificar isso.

# carregar funções
source(
  corrigir_diretorio(
    corrige = "R/contar_obs_UC.R"
  )
)

n_obs_uc <- contar_obs_UC()

n_obs_uc |> 
  datatable(filter= list(
    position = "top"
  )
  )

Adicionar o nome completo da UC na caixa interativa do gráfico. Identificar os plotes com subtítulos ex tentar adicionar título aos plotes

# carregar funções
source(
  corrigir_diretorio(
    corrige = "R/grafico_n_obs_UC_interativo.R"
  )
)

# plotar o o número de observações por UC
dados_selecionados |> 
  grafico_n_obs_UC_interativo()

Tabela interativa com os dados completos de contagem de observações por UC.

dados_selecionados  |>  
  dplyr::count(uc_name, uc_name_abv) |> 
  DT::datatable(filter = list(position = "top"))

1.4.2.6 Quantas observações para cada espécie?

Tabela interativa para consulta do número de observações por espécie.

dados1 |>  
  dplyr::filter(validacao == "E") |> 
  dplyr::count(especie) |> 
  DT::datatable(filter = list(position = "top"))
Error in `dplyr::filter()`:
ℹ In argument: `validacao == "E"`.
Caused by error:
! objeto 'validacao' não encontrado
Backtrace:
  1. DT::datatable(...)
  5. dplyr:::filter.data.frame(dados1, validacao == "E")
  6. dplyr:::filter_rows(.data, dots, by)
  7. dplyr:::filter_eval(...)
  9. mask$eval_all_filter(dots, env_filter)
 10. dplyr (local) eval()

1.4.2.7 Quais e quantas observações para cada espécie por unidades de conservação?

Tabela interativa para consulta do número de observações por espécie e por UC.

1.4.2.8 Quantas unidades de conservação foram amostradas em cada ano?

1.4.2.9 Quantas observações foram realizadas por UC em cada ano?

Tabela interativa para consultar quantas observações foram realizadas por ano em cada UC

1.4.2.10 Quantas observações para cada espécies por ano?

Tabela interativa para consultar quantas observações foram realizadas para cada espécie em cada ano

1.4.2.11 Quantas observações para cada espécies por UC e por ano?

Tabela interativa para consultar quantas observações foram realizadas para cada espécie em cada ano

1.4.2.12 Quantas observações para cada espécies por UC, por estação e por ano?

1.4.3 Selecionando melhores modelos de estudo considerando estratificação espacial/temporal – se há suficiência amostral (60-80 observações) por estrato

  • Possíveis estratificações espaciais – EAs/UCs

                      - UCs/Espécies
    • Possíveis estratificações temporais – Espécie/UC/Ano

1.4.4 Avaliando distância de truncamento

  • Gráficos de distribuição das frequências de ocorrência x distância perpendicular. Arquivos gráfico-exploratorio1.Rmd e gráfico-exploratorio2.Rmd (eu não sei como você fez para incluir aquela linha vermelha com o valor de w no gráfico exploratório 2, mas ficou legal)

1.4.5 Distribuição de distâncias

1.4.6 avaliando covariáveis

– As covariáveis devem ser pensadas de acordo com o grupo taxonômico. Espécies que formam grupos devem ter a covariável ‘size’.

As estratégias de estratificação podem ser substituídas por covariáveis também (estratos espaciais/ ano)

Como covariável temporal, pode se pensar em usar, além do ano, a estação do ano (season), o horário do dia (para animais que variam a atividade). O horário do dia pode ser convertido em tempo após nascer do sol (como no exemplo). Mas para isso é necessário criar essa variável no dataset. E não é trivial porque precisa saber o horário de nascer do sol em cada dia/local para calcular.

1.4.7 gerar gráficos distância x covariável

Exemplo de Gráficos de Marques et al. 2007

1.5 PARTE V – Ajustando os modelos

Esse trabalho do Marque et al. 2007 é uma boa referência de como usar as abordagens CDS global, CDS estratificada e MCDS.

Aqui, é possível testar alguns caminhos de modelos. A estratificação só faz sentido quando o volume de dados for grande. Ainda assim o uso de covariáveis pode substituir a estratificação. Pensar em como orientar o uso dessas abordagens

1.5.1 Modelos pela abordagem CDS – dados globais

  • função ds do Distance (argumentos básicos: truncation; key, adjustment, scale… estudar argumentos para ver se mais algum interessa)

1.5.2 Modelos pela abordagem CDS – dados estratificados

  • Aqui precisa ver direitinho os cuidados que precisa ter para ajustar as funções nos dados estratificados. Acho que faz em blocos. Vai aplicando os mesmos parâmetros para todos os estratos a cada modelo.

  • para cada estrato (espacial ou temporal) usar - função ds do Distance (argumentos básicos: truncation; key, adjustment, scale… estudar argumentos para ver se mais algum interessa)

1.5.3 Modelos pela abordagem MCDS – dados globais

Aqui não faz sentido estratificar

  • função ds do Distance (argumentos básicos: truncation; key, adjustment, scale… estudar argumentos para ver se mais algum interessa… para as covariáveis entra o argumento formula)

Dicas em Miller et al. 2019 sobre covariáveis (ver arquivo no driver).

1.6 PARTE VI – Avaliando os modelos

1.6.1 Ajuste dos modelos

  • função gof_ds

– para gerar Q-Q plots e testes associados

1.6.2 Selecionando modelos (AIC)

– função summarize_ds_models

DICAS EXTRAS DE MILLER et al. 2019

1.7 PARTE VII – PRODUTO FINAL

  • Como organizar

  • Interatividade

2 Criar expressões reativas

reactive() eventReactive()

observe() observeEvent()

reactiveVal() reactiveValues()

isolate()

3 Glossário

LS0tCnRpdGxlOiAiRXNib8OnbyBkbyBmbHV4byBkZSB0cmFiYWxobyBkZSBwcm9kdcOnw6NvIGRvcyBjw7NkaWdvcyIKZGF0ZTogIkNyaWFkbyBlbSAzMSBkZSBtYXLDp28gZGUgMjAyMywgYXR1YWxpemFkbyBlbSBgciBmb3JtYXQoU3lzLnRpbWUoKSwgJyVkIGRlICVCIGRlICVZJylgIgphdXRob3I6IAotIEx1Y2lhbmEgRnVzaW5hdHRvCi0gVml0b3IgQm9yZ2VzLUrDum5pb3IKb3V0cHV0OiAKICBodG1sX25vdGVib29rOgogICAgdG9jOiB0cnVlCiAgICBudW1iZXJfc2VjdGlvbjogdHJ1ZQogICAgCi0tLQoKYGBge3IgY29uZmlndXJhw6fDo28sIGluY2x1ZGU9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9CiMgY2FycmVnYXIgcGFjb3RlcwpsaWJyYXJ5KHJlYWR4bCkKbGlicmFyeShyZWFkcikKbGlicmFyeShmbGV4dGFibGUpCmxpYnJhcnkodGlkeXIpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoRFQpCgojIGNhcnJlZ2FyIGFzIGZ1bsOnw7VlcyBkYSBwYXN0YSBSCiMgY2FycmVnYXIgZnVuw6fDo28gY29ycmlnaXJfZGlyZXRvcmlvLlIKc291cmNlKAogIHBhc3RlMCgKICAgIHN0cmluZ3I6OnN0cl9yZW1vdmUoCiAgICAgIGdldHdkKCksIAogICAgICAnZG9jJwogICAgKSwKICAgICJSL2NvcnJpZ2lyX2RpcmV0b3Jpby5SIgogICkKKSAKCiMgY2FycmVnYXIgZnVuw6fDo28gY2FycmVnYXJfZGFkb3NfZXhwbG9yYWNhby5SCnNvdXJjZSgKICBjb3JyaWdpcl9kaXJldG9yaW8oCiAgICBjb3JyaWdlID0gIlIvY2FycmVnYXJfZGFkb3NfZXhwbG9yYWNhby5SIgogICkKKSAKCiMgY2FycmVnYXIgZnVuw6fDo28gZ3JhZmljb19leHDEum9yYXRvcmlvX2ludGVyYXRpdm8Kc291cmNlKAogIGNvcnJpZ2lyX2RpcmV0b3JpbygKICAgIGNvcnJpZ2UgPSAiUi9ncmFmaWNvX2V4cGxvcmF0b3Jpb19pbnRlcmF0aXZvLlIiCiAgKQopIAoKIyBjYXJyZWdhciBkYWRvcyBkYSBwYXN0YSBkb2MKIyBjYXJyZWdhciBkYWRvc19jb21wbGV0b3MuUiBkYSBwYXN0YSBkb2MKZGFkb3NfY29tcGxldG9zIDwtIHJlYWRyOjpyZWFkX3JkcygKICBjb3JyaWdpcl9kaXJldG9yaW8oCiAgICBjb3JyaWdlID0gImRhdGEvZGFkb3NfY29tcGxldG9zLnJkcyIKICApCikgCgoKIyBjYXJyZWdhciBkYWRvc19maWx0cmFkb3MuUiBkYSBwYXN0YSBkYXRhIHBhcmEgbyBSCmRhZG9zX2ZpbHRyYWRvcyA8LSByZWFkcjo6cmVhZF9yZHMoCiAgY29ycmlnaXJfZGlyZXRvcmlvKAogICAgY29ycmlnZSA9ICJkYXRhL2RhZG9zX2ZpbHRyYWRvcy5yZHMiCiAgKQopIAoKYGBgCgojIEVTQk/Dh08gRkxVWE8gREUgVFJBQkFMSE8gRE8gUFJPRFVUTyAyIC0gQ8OTRElHT1MKCiMjICpQQVJURSBJIOKAkyBDdWlkYWRvcyBhbnRlcyBkZSBjb21lw6dhciBhIHJvZGFyIG9zIGPDs2RpZ29zIG5vIFIqCgpQZW5zYXIgcXVhaXMgb3JpZW50YcOnw7VlcyBzw6NvIG1haXMgZ2VyYWlzIGUgcXVhaXMgc8OjbyBpbXBvcnRhbnRlcyBkZSBhY29tcGFuaGFyIGNhZGEgY8OzZGlnby4KCiMjIyAqUnN0dWRpby9QYWNvdGVzL3ZlcnPDtWVzL3Npc3RlbWFzIG9wZXJhY2lvbmFpcyoKClNvYnJlIG9zIHBhY290ZXMsIHNlcmlhIGJvbSB0ZXIgdW1hIGxpc3RpbmhhIGRlIOKAmGxpYnJhcnnigJkgbm8gaW7DrWNpbyBkZSBjYWRhIGPDs2RpZ28/ClRhbHZleiBjb20gdW1hIGJyZXZlIGV4cGxpY2HDp8OjbyBkbyBxdWUgY2FkYSBwYWNvdGUgZmF6LCB2ZXJzw6NvIG3DrW5pbWEuLi4gbsOjbyBzZWkuCgoqT0JTKjogZXNzYSB0YWJlbGEgw6kgdW1hIHJlZmVyw6puY2lhIHBhcmEgb2J0ZXJtb3MgYXMgdmVyc8O1ZXMgZG9zIHBhY290ZXMgYW8gZmluYWwgZG8gZGVzZW52b2x2aW1lbnRvIGRvIHNjcmlwdC4gRWxhIGVzdMOhIGF1dG9tYXRpemFkYSwgZW50w6NvIHF1YW5kbyB0ZXJtaW5hcm1vcyBlbGUgcHJlY2lzYW1vcyByZWZhemUtbG8gZGUgZm9ybWEgcXVlIG7Do28gZ2VyZSBtYWlzIG11ZGFuw6dhIG5hcyB2ZXJzw7VlcyAodGVtIHF1ZSBmYXplciBhIHRhYmVsYSBuYSBtw6NvIG1lc21vLi4uKS4KCmBgYHtyfQojIGNhcnJlZ2FyIHBhY290ZSBwYXJhIGZvcm1hdGFyIHRhYmVsYQpsaWJyYXJ5KGZsZXh0YWJsZSkKCiMgZ2VyYXIgaW5mb3JtYcOnw7VlcyBzb2JyZSBvcyBwYWNvdGVzIGNhcnJlZ2Fkb3MKaW5mbyA8LSBzZXNzaW9uSW5mbygpCgojIGdlcmFyIHRhYmVsYSBjb20gb3MgcGFjb3RlcyBlIHZlcnPDtWVzCnRpYmJsZTo6dHJpYmJsZSgKICB+UGFjb3RlcywgICAgICAgICAgICAgICAgICAgICAgICAgflZlcnPDo28sCiAgdmVyc2lvbiRsYW5ndWFnZSwgICAgICAgICAgICAgICAgIHZlcnNpb24kdmVyc2lvbi5zdHJpbmcsCiAgaW5mbyRvdGhlclBrZ3MkZHBseXIkUGFja2FnZSwgICAgIGluZm8kb3RoZXJQa2dzJGRwbHlyJFZlcnNpb24sCiAgaW5mbyRvdGhlclBrZ3MkRGlzdGFuY2UkUGFja2FnZSwgIGluZm8kb3RoZXJQa2dzJERpc3RhbmNlJFZlcnNpb24sCiAgaW5mbyRvdGhlclBrZ3MkRFQkUGFja2FnZSwgICAgICAgIGluZm8kb3RoZXJQa2dzJERUJFZlcnNpb24sCiAgaW5mbyRvdGhlclBrZ3MkZmxleHRhYmxlJFBhY2thZ2UsIGluZm8kb3RoZXJQa2dzJGZsZXh0YWJsZSRWZXJzaW9uLAogIGluZm8kb3RoZXJQa2dzJHBsb3RseSRQYWNrYWdlLCAgICBpbmZvJG90aGVyUGtncyRwbG90bHkkVmVyc2lvbiwKICBpbmZvJG90aGVyUGtncyRyZWFkciRQYWNrYWdlLCAgICAgaW5mbyRvdGhlclBrZ3MkcmVhZHIkVmVyc2lvbiwKICBpbmZvJG90aGVyUGtncyR0aWJibGUkUGFja2FnZSwgICAgaW5mbyRvdGhlclBrZ3MkdGliYmxlJFZlcnNpb24sCiAgaW5mbyRvdGhlclBrZ3MkdGlkeXIkUGFja2FnZSwgICAgIGluZm8kb3RoZXJQa2dzJHRpZHlyJFZlcnNpb24sCikgfD4gCiAgcWZsZXh0YWJsZSgpIHw+IAogIHNldF9jYXB0aW9uKAogICAgIlRhYmVsYSB4eCAtIGNvbmZpZ3VyYcOnw6NvIGRlIHBhY290ZXMgbmVjZXNzw6FyaW9zIGUgcmVzcGVjdGl2YXMgdmVyc8O1ZXMgbcOtbmltYXMgcXVlIGRldmVtIHNlciB1dGlsaXphZGFzIHBhcmEgcmVwcm9kdXppciBvcyBjw7NkaWdvcyIKICApCmBgYAoKCiMjIyAqQ3VpZGFkb3MgY29tIGEgcGxhbmlsaGEgLnhsc3ggcXVlIHNlcsOhIGltcG9ydGFkYSAocGFyYSBxdWUgbWFudGVuaGEgbyBwYWRyw6NvIGRhIHBsYW5pbGhhIGRlIHJlZmVyw6puY2lhIGRvIElDTUJpbykqIAoKQWxndW1hcyBmdW7Dp8O1ZXMgZm9yYW0gZXNjcml0YXMgcGFyYSBmdW5jaW9uYXIgdG9tYW5kbyBjb21vIGJhc2UgZGUgZGFkb3MgZGUgcmVmZXLDqm5jaWEgYSBwbGFuaWxoYSBlbSBmb3JtYXRvIGV4Y2VsIGBQbGFuaWxoYSBPZmljaWFsIGNvbnNvbGlkYWRhIGRlIE1hc3RvLWF2ZXMgMjAxNC0yMSBWYWxpZGFkYSBDRU1BVkUgQ1BCIENFTkFQLnhsc3hgIGRpc3BvbmliaWxpemFkYSBwZWxvIFByb2pldG8gTW9uaXRvcmEuIEVzdGFzIGZ1bsOnw7VlcyBjYXJyZWdhbSBvcyBkYWRvcyBlIGZhemVtIHVtYSBzw6lyaWUgZGUgdHJhbnNmb3JtYcOnw7VlcyBwYXJhIGRldm9sdmUtbG9zIG5vIGZvcm1hdG8gcGFkcm9uaXphZG8gZG8gcHJvZ3JhbWEgRElTVEFOQ0UgcGFyYSBXaW5kb3dzLiBQb3J0YW50bywgcGFyYSBnYXJhbnRpciBhIHJlcHJvZHV0aWJpbGlkYWRlIGRvcyBjw7NkaWdvcyBwcm9kdXppZG9zIGVtIHZlcnPDtWVzIGF0dWFsaXphZGFzIGRhIGJhc2UgZGUgZGFkb3MgZG8gTW9uaXRvcmEsIMOpIGltcG9ydGFudGUgdG9tYXIgYWxndW5zIGN1aWRhZG9zLiAKCk8gcHJpbWVpcm8gZSBtYWlzIGltcG9ydGFudGUgY3VpZGFkbyDDqSBtYW50ZXIgb3MgbWVzbW9zIG5vbWVzIGRhcyBjb2x1bmFzIGVtIHZlcnPDtWVzIGF0dWFsaXphZGFzIGRhIGJhc2UgZGUgZGFkb3MgZG8gTW9uaXRvcmEuIEFzIHByaW1laXJhcyBmdW7Dp8O1ZXMsIGFsw6ltIGRlIGNhcnJlZ2FyIG9zIGRhZG9zLCBhcGxpY2FtIHVtYSBzw6lyaWUgZGUgdHJhbnNmb3JtYcOnw7Vlcy4gT3Mgbm9tZXMgZGFzIGNvbHVuYXMgc8OjbyBhbHRlcmFkb3MsIGUgYSBlc3NhcyBzw6NvIGF0cmlidcOtZG9zIHRpcG9zIChkYXRhLCBjYXJhY3RlciwgZmF0b3IgLCBpbnRlaXJvIGUgbnVtw6lyaWNvKSwgbGluaGFzIHPDo28gZWxpbWluYWRhcyBlIG5vdmFzIGNvbHVuYXMgc8OjbyBnZXJlYWRhcy4gUGFyYSBleGVtcGxpZmljYXIsIHZlamEgbyBjw7NkaWdvIGFiYWl4by4gRWxlIGZvaSBlc2NyaXRvIHBhcmEgZXhlY3V0YXIgYXMgcHJpbWVpcmFzIHRyYW5zZm9ybWHDp8O1ZXMgbm9zIGRhZG9zIGUgY29uc3RpdHVpIG8gY29ycG8gZGEgZnVuw6fDo28gYGNhcnJlZ2FyX2RhZG9zX2ZpbHRyYWRvcygpYC4gCgpgYGB7cn0KIyBjYXJyZWdhciBwYWNvdGVzIHBhcmEgbWFuaXB1bGHDp8OjbyBkb3MgZGFkb3MKbGlicmFyeSh0aWR5cikKbGlicmFyeShkcGx5cikKbGlicmFyeShyZWFkeGwpCgojIGNhcnJlZ2FyIGZ1bsOnw6NvIGNvcnJpZ2lyX2RpcmV0b3Jpbwpzb3VyY2UoCiAgcGFzdGUwKAogICAgc3RyaW5ncjo6c3RyX3JlbW92ZSgKICAgICAgZ2V0d2QoKSwgCiAgICAgICdkb2MnCiAgICApLAogICAgIlIvY29ycmlnaXJfZGlyZXRvcmlvLlIiCiAgKQopIAoKIyBjYXJyZWdhciBhIGJhc2UgZGUgZGFkb3MgZG8gTW9uaXRvcmEKZGFkb3NfYnJ1dG9zIDwtIHJlYWRfZXhjZWwoCiAgcGF0aCA9IGNvcnJpZ2lyX2RpcmV0b3JpbygKICAgIGNvcnJpZ2UgPSAiL2RhdGEtcmF3L1BsYW5pbGhhIE9maWNpYWwgY29uc29saWRhZGEgZGUgTWFzdG8tYXZlcyAyMDE0LTIxIFZhbGlkYWRhIENFTUFWRSBDUEIgQ0VOQVAueGxzeCIKICApLAogIHNoZWV0ID0gImRhZG9zIGJydXRvcyIKKQoKIyBnZXJhciBvIGRhdGEuZnJhbWUgZGVzZWphZG8KZGFkb3NfY29tcGxldG9zIDwtIGRhZG9zX2JydXRvcyB8PiAgCiAgIyBzZWxlY2lvbmFyIGFzIGNvbHVuYXMgbmVjZXNzw6FyaWFzIHBhcmEgYXMgYW5hbGlzZXMsIHBhZHJvbml6YW5kbyBvcyBub21lcyBwYXJhIG8gZm9ybWF0byBESVNUQU5DRQogIGRwbHlyOjpzZWxlY3QoCiAgICB1Y19jb2RlID0gQ0RVQywKICAgIHVjX25hbWUgPSBgTG9jYWwgLSBOb21lIGRhIFVuaWRhZGUgZGUgQ29uc2VydmHDp8Ojb2AsCiAgICBlYV9udW1iZXIgPSBgTsO6bWVybyBkYSBFc3Rhw6fDo28gQW1vc3RyYWxgLAogICAgZWFfbmFtZSA9IGBOb21lIGRhIEVBYCwKICAgIHNlYXNvbiA9IGBFc3Rhw6fDo28gZG8gYW5vYCwKICAgIHNhbXBsaW5nX2RheSA9IGBkYXRhIGRhIGFtb3N0cmFnZW1gLAogICAgZGF5X2VmZm9ydCA9IGBFc2ZvcsOnbyBkZSBhbW9zdHJhZ2VtIHRhbWFuaG8gZGEgdHJpbGhhIChtKWAsCiAgICBzcCA9IGBFc3DDqWNpZXMgdmFsaWRhZGFzIHBhcmEgYW7DoWxpc2UgZG8gSUNNQmlvYCwKICAgIGRpc3RhbmNlID0gYGRpc3TDom5jaWEgKG0pICAgICBkbyBhbmltYWwgZW0gcmVsYcOnw6NvIGEgdHJpbGhhYCwKICAgIGdyb3VwX3NpemUgPSBgbsKwIGRlIGFuaW1haXNgLAogICAgb2JzZXJ2YWRvcmVzID0gYG5vbWUgZG9zIG9ic2VydmFkb3Jlc2AKICApIHw+CiAgIyBhdHJpYnVpciBvcyB0aXBvcyBjb3JyZXRvcyDDoHMgY29sdW5hcyBlIGNyaWFyIG5vdmFzIGNvbHVuYXMKICAgIGRwbHlyOjptdXRhdGUoCiAgICAgIHVjX2NhdGVnb3J5ID0gc3RyaW5naTo6c3RyaV9leHRyYWN0X2ZpcnN0X3dvcmRzKAogICAgICB1Y19uYW1lCiAgICApLAogICAgIyBhYnJldmlhIG8gbm9tZSBkYXMgVUNzCiAgICB1Y19uYW1lX2FidiA9IGZvcmNhdHM6Omx2bHNfcmV2YWx1ZSgKICAgICAgdWNfbmFtZSwKICAgICAgbmV3X2xldmVscyA9IGMoCiAgICAgICAgIkVUTSIsICJFTSIsICJFTiIsICJFU0dUIiwgIkZKIiwgIlBDViIsICJQQSIsICJQU0JvYyIsICJQU0JvZCIsICJQU0MiLAogICAgICAgICJQU00iLCAiUFNDIiwgIlBTRCIsICJQU1AiLCAiUFNPIiwgIlBQTiIsICJQQ08iLCAiUEkiLCAiUEphw7oiLCAiUEp1ciIsCiAgICAgICAgIlBNUiIsICJQUyIsICJQViIsICJQQ0EiLCAiUE1UIiwgIlJHIiwgIlJKIiwgIlJUYXAiLCAiUlUiLCAiUkciLAogICAgICAgICJSVHJvbSIsICJSQVQiLCAiUkJBIiwgIlJDSSIsICJSQ00iLCAiUlJDIiwgIlJST1AiLCAiUklBIiwgIlJSQSIsICJSVEEiCiAgICAgICkKICAgICksCiAgICAgICMgYXRyaWJ1aXIgbyB0aXBvIGRhdGEgw6AgY29sdW5hIHNhbXBsaW5nX2RheQogICAgICB5ZWFyID0gbHVicmlkYXRlOjp5ZWFyKAogICAgICAgIHNhbXBsaW5nX2RheQogICAgICApLAogICAgICAjIGF0cmlidWlyIG8gdGlwbyBmYXRvciDDoHMgY29sdW5hcyBkbyB0aXBvIGNhcmFjdGVyCiAgICAgIGFjcm9zcygKICAgICAgICB3aGVyZSgKICAgICAgICAgIGlzLmNoYXJhY3RlcgogICAgICAgICksCiAgICAgICAgYXMuZmFjdG9yCiAgICAgICksCiAgICAgICMgc3Vic3RpdHVpciBzZXBhcmFkb3JlcyBkZSBub21lIHBvciAiLCIKICAgICAgbm92byA9IHN0cmluZ3I6OnN0cl9yZXBsYWNlX2FsbCgKICAgICAgICBvYnNlcnZhZG9yZXMsIAogICAgICAgICIgZSAiLAogICAgICAgICIsICIKICAgICAgKSwKICAgICAgIyBzdWJzdGl0dWlyIHNlcGFyYWRvcmVzIGRlIG5vbWUgcG9yICIsIgogICAgICBub3ZvID0gc3RyaW5ncjo6c3RyX3JlcGxhY2VfYWxsKAogICAgICAgIG5vdm8sIAogICAgICAgICIgRSAiLAogICAgICAgICIsICIKICAgICAgKSwKICAgICAgIyBzdWJzdGl0dWlyIHNlcGFyYWRvcmVzIGRlIG5vbWUgcG9yICIsIgogICAgICBub3ZvID0gc3RyaW5ncjo6c3RyX3JlcGxhY2VfYWxsKAogICAgICAgIG5vdm8sIAogICAgICAgICIvIiwKICAgICAgICAiLCAiCiAgICAgICksCiAgICAgICMgc3Vic3RpdHVpciBzZXBhcmFkb3JlcyBkZSBub21lIHBvciAiLCIKICAgICAgbm92byA9IHN0cmluZ3I6OnN0cl9yZXBsYWNlX2FsbCgKICAgICAgICBub3ZvLCAKICAgICAgICAiOyIsCiAgICAgICAgIiwgIgogICAgICApLAogICAgICAjIHN1YnN0aXR1aXIgc2VwYXJhZG9yZXMgZGUgbm9tZSBwb3IgIiwiCiAgICAgIG5vdm8gPSBzdHJpbmdyOjpzdHJfcmVwbGFjZV9hbGwoCiAgICAgICAgbm92bywgCiAgICAgICAgIiBhICIsCiAgICAgICAgIiwgIgogICAgICApIAogICAgKSB8PgogICMgdHJhbnNmb3JtYXIgb3Mgbm9tZXMgZG9zIG9ic2VydmFkb3JlcyBkYSBjb2x1bmEgbm92byBlbSBjb2x1bmFzIGluZGl2aWR1YWlzCnRpZHlyOjpzZXBhcmF0ZV93aWRlcl9kZWxpbSgKICBub3ZvLCAKICAiLCIsCiAgbmFtZXMgPSBjKAogICAgIm9iczEiLCAib2JzMiIsICJvYnMzIiwgIm9iczQiLCAib2JzNSIsICJvYnM2IgogICksCiAgdG9vX2ZldyA9ICJhbGlnbl9zdGFydCIKKSB8PiAKICAjIGdlcmFyIHVtYSBub3ZhIGNvbHVuYSBudW1iZXJfb2JzZXJ2ZXJzIGNvbSBvIG7Dum1lcm8gdG90YWwgZGUgb2JzZXJ2YWRvcmVzIGVtIHVtIG1lc21vIHRyYW5zZWN0bwogIGRwbHlyOjptdXRhdGUoCiAgICAjIHNlIG8gdmFsb3IgZGEgb2JzZXJ2YcOnw6NvIMOpIGRpZmVyZW50ZSBkZSBOQSwgc3Vic3RpdHVpciBwb3IgMSwgc2UgZm9yIE5BLCBzdWJzdGl0dWlyIHBvciAwCiAgICBvYnMxID0gaWZlbHNlKCFpcy5uYShvYnMxKSwgMSwgMCksCiAgICBvYnMyID0gaWZlbHNlKCFpcy5uYShvYnMyKSwgMSwgMCksCiAgICBvYnMzID0gaWZlbHNlKCFpcy5uYShvYnMzKSwgMSwgMCksCiAgICBvYnM0ID0gaWZlbHNlKCFpcy5uYShvYnM0KSwgMSwgMCksCiAgICBvYnM1ID0gaWZlbHNlKCFpcy5uYShvYnM1KSwgMSwgMCksCiAgICBvYnM2ID0gaWZlbHNlKCFpcy5uYShvYnM2KSwgMSwgMCksCiAgICAjIGdlcmEgbm92YSBjb2x1bmEgbnVtYmVyX29ic2VydmVycyBhIHBhcnRpciBkYSBzb21hIGRhcyBjb2x1bmFzIGRlIG9ic2VydmFkb3JlcyBpbmRpdmlkdWFpcwogICAgbnVtYmVyX29ic2VydmVycyA9IG9iczEgKyBvYnMyICsgb2JzMyArIG9iczQgKyBvYnM1ICsgb2JzNgogICkgfD4gCiAgIyBhZ3J1cGFyIG9zIGRhZG9zIHBlbGFzIGNvbHVuYXMgZWFfbmFtZSBlIHNhbXBsaW5nX2RheQogIGdyb3VwX2J5KAogICAgZWFfbmFtZSwgCiAgICBzYW1wbGluZ19kYXkKICApIHw+IAogICMgYW5pbmhhciBhcyBvYnNlcnZhw6fDtWVzIGFncnVwYWRhcyB1ZW0gbGlzdGFzCiAgbmVzdCgpIHw+IAogICMgY29tcGxldGFyIGNvbSBvIHZhbG9yIGNvcnJldG8gYXMgbGluaGFzIHZhemlhcyBkYXMgZGEgdmFyacOhdmVsIGRheV9lZmZvcnQKICBtdXRhdGUoCiAgICBkYXlfZWZmb3J0MiA9IHB1cnJyOjptYXAoCiAgICAgIGRhdGEsIFwoLngpIHJlcCgKICAgICAgICAueCRkYXlfZWZmb3J0WwogICAgICAgICAgIWlzLm5hKAogICAgICAgICAgICAueCRkYXlfZWZmb3J0CiAgICAgICAgICApCiAgICAgICAgXVsxXQogICAgICApCiAgICApCiAgKSB8PiAKICAjIGRlc2FuaWhhciBvcyBkYWRvcwogIHVubmVzdCgKICAgIGMoCiAgICAgIGRhdGEsIAogICAgICBkYXlfZWZmb3J0MgogICAgKQogICkgfD4gCiAgIyBkZXNhZ3J1cGFyIG9zIGRhZG9zCiAgdW5ncm91cCgpIHw+IAogICMgc2VsZWNpb25hciBhcyBjb2x1bmFzIGRlc2VqYWRhcyBlIGV4Y2x1aXIgYXMgaW5kZXNlamFkYXMKICBzZWxlY3QoCiAgICB0aWR5c2VsZWN0OjpzdGFydHNfd2l0aChjKCJ1YyIsICJlYSIpKSwKICAgIHNlYXNvbiwKICAgIHllYXIsCiAgICBzYW1wbGluZ19kYXksCiAgICBkYXlfZWZmb3J0ID0gZGF5X2VmZm9ydDIsCiAgICBzcDpudW1iZXJfb2JzZXJ2ZXJzLAogICAgLWRheV9lZmZvcnQsCiAgICAtdGlkeXNlbGVjdDo6c3RhcnRzX3dpdGgoIm9icyIpCiAgKSB8PgogICMgZmlsdHJhciBvcyBkYWRvcyBwZWxhIFVDIGUgZXNww6ljaWUgZGVzZWphZGFzCiAgICBkcGx5cjo6ZmlsdGVyKAogICAgICB1Y19uYW1lID09ICJSZXNleCBUYXBhasOzcy1BcmFwaXVucyIsCiAgICAgIHNwID09ICJEYXN5cHJvY3RhIGNyb2Nvbm90YSIKICAgICkgfD4gCiAgcmVsb2NhdGUoCiAgICB1Y19jYXRlZ29yeSwKICAgIC5iZWZvcmUgPSB1Y19uYW1lCiAgKSB8PiAKICByZWxvY2F0ZSgKICAgIHVjX25hbWVfYWJ2LAogICAgLmFmdGVyID0gdWNfbmFtZQogICkKCiMgZ2VyYXIgdGFiZWxhIGRpbsOibWljYSBkb3MgZGFkb3MgYnJ1dG9zCmRhZG9zX2NvbXBsZXRvcyB8PiAKICBzbGljZSgxOjEwMCkgfD4gCiAgRFQ6OmRhdGF0YWJsZShmaWx0ZXIgPSBsaXN0KHBvc2l0aW9uID0gInRvcCIpKQpgYGAKCk8gdHJlY2hvIGRvIGPDs2RpZ28gcXVlIHZhaSBkYSBsaW5oYSAxMDEgYSAxMTMgc2VydmUgc2VsZWNpb25hciBhcGVuYXMgYXMgY29sdW5hcyBkZSBpbnRlcmVzc2UgcHJlc2VudGUgbm9zIGRhZG9zIG9yaWdpbmFpcy4gTm90ZSBxdWUgb3Mgbm9tZXMgZGFzIHBsYW5pbGhhcyBvcmlnaW5haXMgY29uc3RhbSBuZXNzZSB0cmVjaG8uIENhc28gbyBub21lIGRlIHF1YWxxdWUgdW1hIGRlc3NhcyBjb2x1bmFzIHNlamEgYWx0ZXJhZG8gYSBmdW7Dp8OjbyBkZWl4YXLDoSBkZSBmdW5jaW9uYXIuCgpPdXRybyBhc3BlY3RvIGltcG9ydGFudGUgw6kgYSBwcmVzZW7Dp2EgZGUgb2JzZXJ2YcOnw7VlcyBuw6NvIHByZWVuY2hpZGFzIChleC4gY8OpbHVsYXMgdmF6aWFzKSBub3MgZGFkb3Mgb3JpZ2luYWlzLiBBIGZ1bsOnw6NvIGZvaSBkZXNlbmhhIHBhcmEgcmVzb2x2ZXIgYWxndW5zIHByb2JsZW1hcyBwcmVzZW50ZXMgbm9zIGRhZG9zIG9yaWdpbmFpcy4gUG9yIGV4ZW1wbG8sIG5hcyBvIHRyZWNobyBkbyBjw7NkaWdvIGRhcyBsaW5oYXMgeHggYSB4eCBhcyBvYnNlcnZhw6fDtWVzIHZhemlhcyAoYE5BYHMpIHPDo28gc3Vic3RpdHVpZGFzIHBlbG8gdmFsb3IgY29ycmV0byBuYSBjb2x1bmEgYGRheV9lZmZvcnRgLiBFc3NhIGNvcnJlw6fDo28gY29udGlubnVhcsOhIHNlbmRvIHJlYWxpemFkYSBlbSB2ZXJzw7VlcyBhdHVhbGl6YWRhcyBkb3MgZGFkb3MgZG8gTW9uaXRvcmEuIFBvcsOpbSwgc2Ugb3V0cmFzIGNvbHVuYXMgYWzDqW0gZGFzIHF1ZSBlc3TDo28gc2VuZG8gY29ycmlnaWRhcyBwb3NzdWlyZW0gb2JzZXJ2YcOnw7VlcyB2YXppYXMgb3MgZGFkb3Mgc2Vyw6NvIGNhcnJlZ2Fkb3MgZSB0cmFuc2Zvcm1hZG9zLCBwb3LDqW0gb3V0cmFzIGZ1bsOnw7VlcyBwb2RlbSB0ZXIgbyBzZXUgZnVuY2lvbmFtZW50byBjb21wcm9tZXRpZG8uIFBvciBleGVtcGxvLi4uIChmdW7Dp8O1ZXMgZGUgdmlzdWFsaXphw6fDo28gZSBkbyBwYWNvdGUgZGlzdGFuY2UgcXVlIHBvZGVtIG5hw7UgZnVuY2lvbmFyIGRldmlkbyBhIGF1c8OqbmNpYSBkZSBvYnNlcnZhw6fDo28pCgpPdXRyb3MgY3VpZGFkb3MuLi4KCkltYWdpbmFuZG8gcXVlIGEgcGxhbmlsaGEgZGUgZGFkb3MgZG8gbW9uaXRvcmEgw6kgYWxnbyBkaW7Dom1pY28sIHF1ZSBvIG5vbWUgZGFzIGNvbHVuYXMgcG9kZSBzZXIgZWRpdGFkby4uLgoKIyMjICpDb21vIGFicmlyIG9zIGFycXVpdm9zOiBjb21vIHNhbHZhciBlIGRlc2NvbXBhY3RhciBhIHBhc3RhLiBBYnJpciBwcm9qZXRvKgoKVW0gcGFzc28gYSBwYXNzbyBkZSBjb21vIHNhbHZhciBhcnF1aXZvIGNvbSBvcyBjw7NkaWdvcyBlIGFicmlyLi4gUG9yIGV4ZW1wbG8sIGRhIGZvcm1hIGNvbW8gZXN0w6Egw6kgaW50ZXJlc3NhbnRlIGRlc2NvbXBhY3RhciBhIHBhc3RhIGUgYWNlc3NhciBvcyBhcnF1aXZvcyBhYnJpbmRvIG8gcHJvamV0by4gQWNobyBxdWUgaXNzbyBwb2RlIG11ZGFyLCBkZXBlbmRlbmRvIGRlIGNvbW8gdmllcm1vcyBhIGVudHJlZ2FyIG8gcHJvZHV0byBmaW5hbC4gRW50w6NvIHBvZGVtb3MgcGVuc2FyIG5lc3NhIGV4cGxpY2HDp8OjbyBubyBmaW5hbC4KCiMjIyAqQ3VpZGFkb3MgY29tIGRpcmV0w7NyaW8qCgpTZSBhIGdlbnRlIGFpbmRhIHByZWNpc2FyIHRlciBhbGd1bSB0aXBvIGRlIHByZW9jdXBhw6fDo28gcXVhbnRvIGEgaXNzby4gQWNobyBxdWUgbsOjby4KCiMjIyAqQ29tbyByb2RhciBjYWRhIHRpcG8gZGUgYXJxdWl2byAobWFya2Rvd24sIHNoaW55KSoKCk7Do28gw6kgdHJpdmlhbCBwYXJhIHF1ZW0gbsOjbyBlc3TDoSBhY29zdHVtYWRvLi4uIHVzYXIgcnVuQXBwLCBrbml0Li4uIGF0w6kgbWVzbW8gbyBzaGlmdCtlbnRlciBwYXJhIHJvZGFyIGFzIGxpbmhhcyBkZSBjb21hbmRvIHVtYSBhIHVtYQoKIyMgKlBBUlRFIElJIOKAkyBDYXJyZWdhbmRvIG9zIGRhZG9zIHBhcmEgbyBSKgoKIyMjICpEYWRvcyBicnV0b3MqCgotIHRvZGFzIGVzcMOpY2llcy9VQ3Mg4oCTIGNhcnJlZ2FfZGFkb3NfMS5SbWQKYGBge3J9CiMgY2FycmVnYXIgcGFjb3RlCmxpYnJhcnkoRFQpCgojIGNhcnJlZ2FyIGEgZnVuw6fDo28Kc291cmNlKAogIGNvcnJpZ2lyX2RpcmV0b3JpbygKICBjb3JyaWdlID0gJ1IvY2FycmVnYXJfZGFkb3NfY29tcGxldG9zLlInCiAgKQopCgojIGNhcnJlZ2FyIGRhZG9zIHBhcmEgbyBSCmRhZG9zX2NvbXBsZXRvcyA8LSBjYXJyZWdhcl9kYWRvc19jb21wbGV0b3MoKSAKCgpkYWRvc19jb21wbGV0b3MgfD4gCiAgc2xpY2UoMTo1MDApIHw+IAogIGRhdGF0YWJsZSgKICAgIGZpbHRlciA9IGxpc3QoCiAgICAgIHBvc2l0aW9uID0gInRvcCIKICAgICkKICApCmBgYAoKCiMjIyAqRGFkb3MgZmlsdHJhZG9zKgoKLSBwb3IgZXNww6ljaWUvVUMg4oCTIGNhcnJlZ2FfZGFkb3NfMi5SbWQKYXTDqSBvIG1vbWVudG8gdXNhZG8gY29tIG8gZXhlbXBsbyBkYSBjdXRpYSBuYSBSZXNleCBUYXBhasOzcy1BcmFwaXVucwoKYGBge3J9CiMgY2FycmVnYXIgYSBmdW7Dp8Ojbwpzb3VyY2UoCiAgY29ycmlnaXJfZGlyZXRvcmlvKAogICAgIGNvcnJpZ2UgPSAnUi9jYXJyZWdhcl9kYWRvc19maWx0cmFkb3MuUicKICApCiAgKQoKIyBjYXJyZWdhciBkYWRvcyBwYXJhIG8gUgpkYWRvc19maWx0cmFkb3MgPC0gY2FycmVnYXJfZGFkb3NfZmlsdHJhZG9zKAogIGRhZG9zID0gY29ycmlnaXJfZGlyZXRvcmlvKAogICAgY29ycmlnZSA9ICAnZGF0YS1yYXcvZGFkb3MtYnJ1dG9zLnhsc3gnCiAgKSwKICBub21lX3VjID0gIlJlc2V4IFRhcGFqw7NzLUFyYXBpdW5zIiwKICBub21lX3NwID0gIkRhc3lwcm9jdGEgY3JvY29ub3RhIgopCgpkYWRvc19maWx0cmFkb3MgfD4gCiAgZGF0YXRhYmxlKAogICAgZmlsdGVyID0gbGlzdCgKICAgICAgcG9zaXRpb24gPSAidG9wIgogICAgKQogICkKYGBgCgojIyAqUGFydGUgSUlJIOKAkyBUcmFuc2Zvcm1hbmRvIGRhZG9zIHBhcmEgRGlzdGFuY2UqCgojIyMgKkRhZG9zIGNvbXBsZXRvcyoKCi0gdG9kYXMgZXNww6ljaWVzL1VDcyDigJMgdHJhbnNmb3JtYV9wYXJhX2Rpc3RhbmNlUi5SbWQKCmBgYHtyfQojIGNhcnJlZ2FyIGFzIGZ1bsOnw7Vlcwpzb3VyY2UoCiAgY29ycmlnaXJfZGlyZXRvcmlvKAogICAgY29ycmlnZSA9ICJSL2NhcnJlZ2FyX2RhZG9zX2NvbXBsZXRvcy5SIgogICkKICApIAoKc291cmNlKAogIGNvcnJpZ2lyX2RpcmV0b3JpbygKICAgIGNvcnJpZ2UgPSAiUi90cmFuc2Zvcm1hX3BhcmFfZGlzdGFuY2VSLlIiCiAgKQopCgojIGNhcnJlZ2FyIGRhZG9zIHBhcmEgbyBSCmRhZG9zX2NvbXBsZXRvcyA8LSBjYXJyZWdhcl9kYWRvc19jb21wbGV0b3MoKQoKIyB0cmFuc2Zvcm1hciBvcyBkYWRvcyBwYXJhIG8gZm9ybWF0byBkbyBEaXN0YW5jZQpkYWRvc19kaXN0YW5jZVJfY29tcGxldG8gPC0gdHJhbnNmb3JtYV9wYXJhX2Rpc3RhbmNlUigKICBkYWRvc19jb21wbGV0b3MKKQoKZGFkb3NfZGlzdGFuY2VSX2NvbXBsZXRvIHw+IAogIHNsaWNlKDE6NTAwKSB8PiAKICBkYXRhdGFibGUoCiAgICBmaWx0ZXIgPSBsaXN0KAogICAgICBwb3NpdGlvbiA9ICJ0b3AiCiAgICApCiAgKQpgYGAKCgpgYGB7cn0KIyBjYXJyZWdhciBhcyBmdW7Dp8O1ZXMKc291cmNlKAogIGNvcnJpZ2lyX2RpcmV0b3JpbygKICBjb3JyaWdlID0gIlIvdHJhbnNmb3JtYV9wYXJhX2Rpc3RhbmNlUl9jb3ZhcmlhdmVpcy5SIgopCikKCiMgY2FycmVnYXIgZGFkb3MgcGFyYSBvIFIKZGFkb3NfZmlsdHJhZG9zIDwtIHJlYWRfcmRzKAogIGZpbGUgPSBjb3JyaWdpcl9kaXJldG9yaW8oCiAgICBjb3JyaWdlID0gImRhdGEvZGFkb3NfZmlsdHJhZG9zLnJkcyIKICApCiAgKQoKIyB0cmFuc2Zvcm1hciBvcyBkYWRvcyBwYXJhIG8gZm9ybWF0byBkbyBEaXN0YW5jZQpkYWRvc19kaXN0YW5jZVJfY292YXJpYXZlaXMgPC0gdHJhbnNmb3JtYV9wYXJhX2Rpc3RhbmNlUl9jb3ZhcmlhdmVpcygKICBkYWRvcyA9IGRhZG9zX2ZpbHRyYWRvcwopCgpkYWRvc19kaXN0YW5jZVJfY292YXJpYXZlaXMgfD4gCiAgc2xpY2UoMTo1MDApIHw+IAogIGRhdGF0YWJsZSgKICAgIGZpbHRlciA9IGxpc3QoCiAgICAgIHBvc2l0aW9uID0gInRvcCIKICAgICkKICApCmBgYAoKIyMjICpEYWRvcyBzZWxlY2lvbmFkb3MqIAoKU2lzdGVtYXRpemFyIG9zIGNyaXTDqXJpb3MgdXRpbGl6YWRvcyBwYXJhIGVsaW1pbmFyIG9ic2VydmHDp8O1ZXMgKGxpbmhhcykuCgotIGVzcMOpY2llcyB2YWxpZGFkYXMKLSAuLi4KCiMjIFF1YW50YXMgb2JzZXJ2YcOnw7VlcyBmb3JhbSB2YWxpZGFkYXMgcGFyYSBxdWFpcyBuw612ZWlzIHRheG9uw7RtaWNvcz8KCmBgYHtyfQpuX3NwX3ZhbGlkYWRhIDwtIGRhZG9zX2NvbXBsZXRvcyB8PiAKICBjb3VudCh2YWxpZGF0aW9uKQpgYGAKCkZvcmFtIHNlbGVjaW9uYWRhcyBhcGVuYXMgYXMgb2JzZXJ2YcOnw7VlcyB2YWxpZGFkYXMgYW8gbsOtdmVsIGRlIGVzcMOpY2llLCBzb21hbmRvIHVtIHRvdGFsIGByIG5fc3BfdmFsaWRhZGEkblsxXWAgb2JzZXJ2YcOnw7Vlcy4KCmBgYHtyfQojIGNhcnJlZ2FyIGFzIGZ1bsOnw7Vlcwpzb3VyY2UoCiAgY29ycmlnaXJfZGlyZXRvcmlvKAogICAgY29ycmlnZSA9ICJSL2NhcnJlZ2FyX2RhZG9zX2NvbXBsZXRvcy5SIgogICkKICApIApzb3VyY2UoCiAgY29ycmlnaXJfZGlyZXRvcmlvKAogICAgY29ycmlnZSA9ICJSL2dyYWZpY29fbl9zcF92YWxpZGFkYXMuUiIKICApCikKCiMgY2FycmVnYXIgZGFkb3MgcGFyYSBvIFIKZGFkb3NfY29tcGxldG9zIDwtIGNhcnJlZ2FyX2RhZG9zX2NvbXBsZXRvcygpCgojIGdlcmFyIGdyw6FmaWNvIGNvbSBuw7ptZXJvIG9ic2VydmHDp8O1ZXMgdmFsaWRhZGFzIHBhcmEgY2FkYSBuw612ZWwgdGF4b27DtG1pY28KZ3JhZmljb19uX3NwX3ZhbGlkYWRhcygpCmBgYAoKYGBge3J9CiMgY2FycmVnYXIgZnVuw6fDo28gY2FycmVnYXIgZGFkb3Mgc2VsZWNpb25hZG9zCnNvdXJjZSgKICBjb3JyaWdpcl9kaXJldG9yaW8oCiAgICBjb3JyaWdlID0gIlIvY2FycmVnYXJfZGFkb3Nfc2VsZWNpb25hZG9zLlIiCiAgKQopCgojIGdlcmFyIHRhYmVsYSBkZSBkYWRvcyBzZWxlY2lvbmFkb3MKZGFkb3Nfc2VsZWNpb25hZG9zIDwtIGNhcnJlZ2FyX2RhZG9zX3NlbGVjaW9uYWRvcygpCgpkYWRvc19zZWxlY2lvbmFkb3MgfD4gCiAgc2xpY2UoMTo1MDApIHw+IAogIGRhdGF0YWJsZSgKICAgIGZpbHRlciA9IGxpc3QoCiAgICAgIHBvc2l0aW9uID0gInRvcCIKICAgICkKICApCmBgYAoKIyMjICpQQVJURSBJViDigJMgRXhwbG9yYW5kbyBvcyBkYWRvcyoKCiMjIyAqU2VsZWNpb25hbmRvIG9zIG1lbGhvcmVzIG1vZGVsb3MgZGUgZXN0dWRvIGRlIGFjb3JkbyBjb20gb3MgZGFkb3MqCgpDcml0xZVpb3M6CgotIGVzcMOpY2llcyBjb20gbWFpb3Igdm9sdW1lIGRlIGRhZG9zIHRvdGFsCi0gbWFpb3Igdm9sdW1lIGRlIGRhZG9zIHBvciBVQwog4oCTICBleHBsb3Jhw6fDo29fMDEubmIuaHRtbCAoYWNobyBxdWUgbyAuUm1kIHBhcmEgZ2VyYXIgZXNzZSBodG1sIG7Do28gZXN0w6EgbmEgcGFzdGEgTW9uaXRvcmEpLiBFdSB0aW5oYSBnb3N0YWRvIGJhc3RhbnRlIGRlc3NlIGRvY3VtZW50bywgY29tIGFzIHRhYmVsYXMgZGluw6JtaWNhcy4gVGFsdmV6IGTDqiBwYXJhIHNlbGVjaW9uYXIgYXMgcGVyZ3VudGFzIHF1ZSBzw6NvIHbDoWxpZGFzIGRlIGRlaXhhci8gdGlyYXIvIGluY2x1aXIuCgpXV0YgLSBQcm9qZXRvIE1vbml0b3JhCgojIyMjICpFeHBsb3Jhw6fDo28gZGUgZGFkb3MqCgojIyMjICpJbmZvcm1hw6fDtWVzIGLDoXNpY2FzKgoKIyMjIyAqUXVhbnRhcyB1bmlkYWRlcyBkZSBjb25zZXJ2YcOnw6NvIGFvIHRvZG8/KgoKYGBge3Igbl9kZV91Y3N9CnNvdXJjZSgKICBjb3JyaWdpcl9kaXJldG9yaW8oCiAgICBjb3JyaWdlID0gIlIvY29udGFyX1VDcy5SIgogICkKKQoKbl91Y3MgPC0gY29udGFyX1VDcygKICBkYWRvc19zZWxlY2lvbmFkb3MKKQpgYGAKCk9zIGRhZG9zIHPDo28gcHJvdmVuaWVudGVzIGRlIGByIG5fdWNzYCB1bmlkYWRlcyBkZSBjb25zZXJ2YcOnw6NvIGFvIHRvZG8uCgojIyMjICpRdWFudGFzIGVzcMOpY2llcyBhbyB0b2RvPyoKCmBgYHtyfQpzb3VyY2UoCiAgY29ycmlnaXJfZGlyZXRvcmlvKAogICAgY29ycmlnZSA9ICJSL2NvbnRhcl9zcC5SIgogICkKKQoKbl9zcCA8LSBjb250YXJfc3AoCiAgZGFkb3NfY29tcGxldG9zCikKYGBgCgpGb3JhbSBjb2xldGFkb3MgZGFkb3MgcGFyYSBgciBuX3NwYCBlc3DDqWNpZXMuCgojIyMjICpRdWFudGFzIG9ic2VydmHDp8O1ZXMgcG9yIHVuaWRhZGUgZGUgY29uc2VydmHDp8OjbyBhbyB0b2RvPyoKCkFzIFVDJ3MgZm9yYW0gZmlsdHJhZGFzIGRlIGFjb3JkbyBjb20gbyBuw7ptZXJvIGRlIG9ic2VydmHDp8O1ZXMgcGVybWl0aXIgYSB2aXN1YWxpemHDp8Ojby4KCkEgZnVuw6fDo28gZGUgY29udGFnZW0gZGUgVUMncyBnZXJvdSA0MCBVQydzLCBtYXMgc8OzIGjDoSBvYnNlcnZhw6fDtWVzIHBhcmEgMzguICpMZW1icmFyIGRlIHZlcmlmaWNhciBpc3NvKi4KCmBgYHtyfQojIGNhcnJlZ2FyIGZ1bsOnw7Vlcwpzb3VyY2UoCiAgY29ycmlnaXJfZGlyZXRvcmlvKAogICAgY29ycmlnZSA9ICJSL2NvbnRhcl9vYnNfVUMuUiIKICApCikKCm5fb2JzX3VjIDwtIGNvbnRhcl9vYnNfVUMoKQoKbl9vYnNfdWMgfD4gCiAgZGF0YXRhYmxlKGZpbHRlcj0gbGlzdCgKICAgIHBvc2l0aW9uID0gInRvcCIKICApCiAgKQpgYGAKCipBZGljaW9uYXIgbyBub21lIGNvbXBsZXRvIGRhIFVDIG5hIGNhaXhhIGludGVyYXRpdmEgZG8gZ3LDoWZpY28qLgoqSWRlbnRpZmljYXIgb3MgcGxvdGVzIGNvbSBzdWJ0w610dWxvcyBleCB0ZW50YXIgYWRpY2lvbmFyIHTDrXR1bG8gYW9zIHBsb3RlcyoKCmBgYHtyLCBmaWcuaGVpZ2h0PTIwfQojIGNhcnJlZ2FyIGZ1bsOnw7Vlcwpzb3VyY2UoCiAgY29ycmlnaXJfZGlyZXRvcmlvKAogICAgY29ycmlnZSA9ICJSL2dyYWZpY29fbl9vYnNfVUNfaW50ZXJhdGl2by5SIgogICkKKQoKIyBwbG90YXIgbyBvIG7Dum1lcm8gZGUgb2JzZXJ2YcOnw7VlcyBwb3IgVUMKZGFkb3Nfc2VsZWNpb25hZG9zIHw+IAogIGdyYWZpY29fbl9vYnNfVUNfaW50ZXJhdGl2bygpCmBgYAoKVGFiZWxhIGludGVyYXRpdmEgY29tIG9zIGRhZG9zIGNvbXBsZXRvcyBkZSBjb250YWdlbSBkZSBvYnNlcnZhw6fDtWVzIHBvciBVQy4KYGBge3J9CmRhZG9zX3NlbGVjaW9uYWRvcyAgfD4gIAogIGRwbHlyOjpjb3VudCh1Y19uYW1lLCB1Y19uYW1lX2FidikgfD4gCiAgRFQ6OmRhdGF0YWJsZShmaWx0ZXIgPSBsaXN0KHBvc2l0aW9uID0gInRvcCIpKQpgYGAKCiMjIyMgKlF1YW50YXMgb2JzZXJ2YcOnw7VlcyBwYXJhIGNhZGEgZXNww6ljaWU/KgoKVGFiZWxhIGludGVyYXRpdmEgcGFyYSBjb25zdWx0YSBkbyBuw7ptZXJvIGRlIG9ic2VydmHDp8O1ZXMgcG9yIGVzcMOpY2llLgpgYGB7cn0KZGFkb3MxIHw+ICAKICBkcGx5cjo6ZmlsdGVyKHZhbGlkYWNhbyA9PSAiRSIpIHw+IAogIGRwbHlyOjpjb3VudChlc3BlY2llKSB8PiAKICBEVDo6ZGF0YXRhYmxlKGZpbHRlciA9IGxpc3QocG9zaXRpb24gPSAidG9wIikpCmBgYAoKIyMjIyAqUXVhaXMgZSBxdWFudGFzIG9ic2VydmHDp8O1ZXMgcGFyYSBjYWRhIGVzcMOpY2llIHBvciB1bmlkYWRlcyBkZSBjb25zZXJ2YcOnw6NvPyoKClRhYmVsYSBpbnRlcmF0aXZhIHBhcmEgY29uc3VsdGEgZG8gbsO6bWVybyBkZSBvYnNlcnZhw6fDtWVzIHBvciBlc3DDqWNpZSBlIHBvciBVQy4KYGBge3J9CmRhZG9zMSB8PiAgCiAgZHBseXI6OmZpbHRlcih2YWxpZGFjYW8gPT0gIkUiKSB8PiAKICBkcGx5cjo6Y291bnQodWNzLCBlc3BlY2llKSB8PiAKICBEVDo6ZGF0YXRhYmxlKGZpbHRlciA9IGxpc3QocG9zaXRpb24gPSAidG9wIikpCmBgYAoKIyMjIyAqUXVhbnRhcyB1bmlkYWRlcyBkZSBjb25zZXJ2YcOnw6NvIGZvcmFtIGFtb3N0cmFkYXMgZW0gY2FkYSBhbm8/KgoKYGBge3IsIGVjaG89RkFMU0V9CmRhZG9zMSB8PiAgCiAgZHBseXI6OmNvdW50KGFubywgdWNzKSB8PiAgCiAgZHBseXI6Omdyb3VwX2J5KGFubykgfD4gIAogIGRwbHlyOjpjb3VudCh1Y3MpIHw+ICAKICBkcGx5cjo6c3VtbWFyaXNlKG5fdWNzID0gc3VtKG4pKQpgYGAKCiMjIyMgKlF1YW50YXMgb2JzZXJ2YcOnw7VlcyBmb3JhbSByZWFsaXphZGFzIHBvciBVQyBlbSBjYWRhIGFubz8qCgpUYWJlbGEgaW50ZXJhdGl2YSBwYXJhIGNvbnN1bHRhciBxdWFudGFzIG9ic2VydmHDp8O1ZXMgZm9yYW0gcmVhbGl6YWRhcyBwb3IgYW5vIGVtIGNhZGEgVUMKYGBge3J9CmRhZG9zMSB8PiAgCiAgZHBseXI6OmNvdW50KGFubywgdWNzKSB8PiAKICBEVDo6ZGF0YXRhYmxlKGZpbHRlciA9IGxpc3QocG9zaXRpb24gPSAidG9wIikpCmBgYAoKIyMjIyBRdWFudGFzIG9ic2VydmHDp8O1ZXMgcGFyYSBjYWRhIGVzcMOpY2llcyBwb3IgYW5vPwoKVGFiZWxhIGludGVyYXRpdmEgcGFyYSBjb25zdWx0YXIgcXVhbnRhcyBvYnNlcnZhw6fDtWVzIGZvcmFtIHJlYWxpemFkYXMgcGFyYSBjYWRhIGVzcMOpY2llIGVtIGNhZGEgYW5vCmBgYHtyfQpkYWRvczEgfD4gIAogIGRwbHlyOjpjb3VudChhbm8sIGVzcGVjaWUpIHw+IAogIERUOjpkYXRhdGFibGUoZmlsdGVyID0gbGlzdChwb3NpdGlvbiA9ICJ0b3AiKSkKYGBgCgojIyMjICpRdWFudGFzIG9ic2VydmHDp8O1ZXMgcGFyYSBjYWRhIGVzcMOpY2llcyBwb3IgVUMgZSBwb3IgYW5vPyoKClRhYmVsYSBpbnRlcmF0aXZhIHBhcmEgY29uc3VsdGFyIHF1YW50YXMgb2JzZXJ2YcOnw7VlcyBmb3JhbSByZWFsaXphZGFzIHBhcmEgY2FkYSBlc3DDqWNpZSBlbSBjYWRhIGFubwoKYGBge3J9CmRhZG9zMSB8PiAgCiAgZHBseXI6OmNvdW50KGFubywgdWNzLCBlc3BlY2llKSB8PiAKICBEVDo6ZGF0YXRhYmxlKGZpbHRlciA9IGxpc3QocG9zaXRpb24gPSAidG9wIikpCmBgYAoKIyMjIyAqUXVhbnRhcyBvYnNlcnZhw6fDtWVzIHBhcmEgY2FkYSBlc3DDqWNpZXMgcG9yIFVDLCBwb3IgZXN0YcOnw6NvIGUgcG9yIGFubz8qCgpgYGB7cn0KZGFkb3MxIHw+ICAKICBkcGx5cjo6Y291bnQoYW5vLCBzZWFzb24sIHVjX25hbWUsIHNwKSB8PiAKICBEVDo6ZGF0YXRhYmxlKGZpbHRlciA9IGxpc3QocG9zaXRpb24gPSAidG9wIikpCmBgYAoKIyMjICpTZWxlY2lvbmFuZG8gbWVsaG9yZXMgbW9kZWxvcyBkZSBlc3R1ZG8gY29uc2lkZXJhbmRvIGVzdHJhdGlmaWNhw6fDo28gZXNwYWNpYWwvdGVtcG9yYWwg4oCTIHNlIGjDoSBzdWZpY2nDqm5jaWEgYW1vc3RyYWwgKDYwLTgwIG9ic2VydmHDp8O1ZXMpIHBvciBlc3RyYXRvKgoKLSBQb3Nzw612ZWlzIGVzdHJhdGlmaWNhw6fDtWVzIGVzcGFjaWFpcyDigJMgRUFzL1VDcwoKCQkJCQkgICAgLSBVQ3MvRXNww6ljaWVzCgoJLSBQb3Nzw612ZWlzIGVzdHJhdGlmaWNhw6fDtWVzIHRlbXBvcmFpcyDigJMgRXNww6ljaWUvVUMvQW5vIAoKIyMjICpBdmFsaWFuZG8gZGlzdMOibmNpYSBkZSB0cnVuY2FtZW50byAqCgotIEdyw6FmaWNvcyBkZSBkaXN0cmlidWnDp8OjbyBkYXMgZnJlcXXDqm5jaWFzIGRlIG9jb3Jyw6puY2lhIHggZGlzdMOibmNpYSBwZXJwZW5kaWN1bGFyLiBBcnF1aXZvcyBncsOhZmljby1leHBsb3JhdG9yaW8xLlJtZCBlIGdyw6FmaWNvLWV4cGxvcmF0b3JpbzIuUm1kIChldSBuw6NvIHNlaSBjb21vIHZvY8OqIGZleiBwYXJhIGluY2x1aXIgYXF1ZWxhIGxpbmhhIHZlcm1lbGhhIGNvbSBvIHZhbG9yIGRlIHcgbm8gZ3LDoWZpY28gZXhwbG9yYXTDs3JpbyAyLCBtYXMgZmljb3UgbGVnYWwpCgojIyMgKkRpc3RyaWJ1acOnw6NvIGRlIGRpc3TDom5jaWFzKgoKYGBge3IgZGlzdHJpYnVpY2FvX2RzaXRhbmNpYSwgd2FybmluZz1GQUxTRX0KIyBjYXJyZWdhciBkYWRvc19maWx0cmFkb3MuUiBkYSBwYXN0YSBkYXRhIHBhcmEgbyBSCmRhZG9zX2ZpbHRyYWRvcyA8LSByZWFkcjo6cmVhZF9yZHMoY29ycmlnaXJfZGlyZXRvcmlvKGNvcnJpZ2UgPSAiZGF0YS9kYWRvc19maWx0cmFkb3MucmRzIikpIAoKIyBnZXJhciBvIGdyw6FmaWNvIGV4cGxvcmF0w7NyaW8gZGEgZGlzdHJpYnVpw6fDo28gZGUgZGlzdMOibmNpYXMgcGVycGVuZGljdWxhcmVzIHBhcmEgYSBlc3DDqWNpZXMgRGFzeXJvY3RhIGNyb2Nvbm90YSBuYSBSZXNleCBUYXBhasOzcy1BcmFwaXVucwpmaWcgPC0gZGFkb3NfZmlsdHJhZG9zIHw+CiAgIyBleGNsdWlyIE5BJ3MgZGEgdmFyacOhdmVsIGRpc3RhbmNlCiAgdGlkeXI6OmRyb3BfbmEoZGlzdGFuY2UpIHw+IAogIGdyYWZpY29fZXhwbG9yYXRvcmlvMygpCgpmaWcKYGBgCgojIyMgKmF2YWxpYW5kbyBjb3ZhcmnDoXZlaXMqCgrigJMgQXMgY292YXJpw6F2ZWlzIGRldmVtIHNlciBwZW5zYWRhcyBkZSBhY29yZG8gY29tIG8gZ3J1cG8gdGF4b27DtG1pY28uIEVzcMOpY2llcyBxdWUgZm9ybWFtIGdydXBvcyBkZXZlbSB0ZXIgYSBjb3ZhcmnDoXZlbCDigJhzaXpl4oCZLiAKCkFzIGVzdHJhdMOpZ2lhcyBkZSBlc3RyYXRpZmljYcOnw6NvIHBvZGVtIHNlciBzdWJzdGl0dcOtZGFzIHBvciBjb3ZhcmnDoXZlaXMgdGFtYsOpbSAoZXN0cmF0b3MgZXNwYWNpYWlzLyBhbm8pCgpDb21vIGNvdmFyacOhdmVsIHRlbXBvcmFsLCBwb2RlIHNlIHBlbnNhciBlbSB1c2FyLCBhbMOpbSBkbyBhbm8sIGEgZXN0YcOnw6NvIGRvIGFubyAoc2Vhc29uKSwgbyBob3LDoXJpbyBkbyBkaWEgKHBhcmEgYW5pbWFpcyBxdWUgdmFyaWFtIGEgYXRpdmlkYWRlKS4gTyBob3LDoXJpbyBkbyBkaWEgcG9kZSBzZXIgY29udmVydGlkbyBlbSB0ZW1wbyBhcMOzcyBuYXNjZXIgZG8gc29sIChjb21vIG5vIGV4ZW1wbG8pLiBNYXMgcGFyYSBpc3NvIMOpIG5lY2Vzc8OhcmlvIGNyaWFyIGVzc2EgdmFyacOhdmVsIG5vIGRhdGFzZXQuIEUgbsOjbyDDqSB0cml2aWFsIHBvcnF1ZSBwcmVjaXNhIHNhYmVyIG8gaG9yw6FyaW8gZGUgbmFzY2VyIGRvIHNvbCBlbSBjYWRhIGRpYS9sb2NhbCBwYXJhIGNhbGN1bGFyLgoKIyMjICpnZXJhciBncsOhZmljb3MgZGlzdMOibmNpYSB4IGNvdmFyacOhdmVsKgoKRXhlbXBsbyBkZSBHcsOhZmljb3MgZGUgTWFycXVlcyBldCBhbC4gMjAwNwoKIyMgKlBBUlRFIFYg4oCTIEFqdXN0YW5kbyBvcyBtb2RlbG9zKgoKRXNzZSB0cmFiYWxobyBkbyBNYXJxdWUgZXQgYWwuIDIwMDcgw6kgdW1hIGJvYSByZWZlcsOqbmNpYSBkZSBjb21vIHVzYXIgYXMgYWJvcmRhZ2VucyBDRFMgZ2xvYmFsLCBDRFMgZXN0cmF0aWZpY2FkYSBlIE1DRFMuCgpBcXVpLCDDqSBwb3Nzw612ZWwgdGVzdGFyIGFsZ3VucyBjYW1pbmhvcyBkZSBtb2RlbG9zLiBBIGVzdHJhdGlmaWNhw6fDo28gc8OzIGZheiBzZW50aWRvIHF1YW5kbyBvIHZvbHVtZSBkZSBkYWRvcyBmb3IgZ3JhbmRlLiBBaW5kYSBhc3NpbSBvIHVzbyBkZSBjb3ZhcmnDoXZlaXMgcG9kZSBzdWJzdGl0dWlyIGEgZXN0cmF0aWZpY2HDp8Ojby4gUGVuc2FyIGVtIGNvbW8gb3JpZW50YXIgbyB1c28gZGVzc2FzIGFib3JkYWdlbnMKCiMjIyAqTW9kZWxvcyBwZWxhIGFib3JkYWdlbSBDRFMg4oCTIGRhZG9zIGdsb2JhaXMqCgotIGZ1bsOnw6NvIGRzIGRvIERpc3RhbmNlIChhcmd1bWVudG9zIGLDoXNpY29zOiB0cnVuY2F0aW9uOyBrZXksIGFkanVzdG1lbnQsIHNjYWxlLi4uIGVzdHVkYXIgYXJndW1lbnRvcyBwYXJhIHZlciBzZSBtYWlzIGFsZ3VtIGludGVyZXNzYSkKCiMjIyAqTW9kZWxvcyBwZWxhIGFib3JkYWdlbSBDRFMg4oCTIGRhZG9zIGVzdHJhdGlmaWNhZG9zKgoKLSBBcXVpIHByZWNpc2EgdmVyIGRpcmVpdGluaG8gb3MgY3VpZGFkb3MgcXVlIHByZWNpc2EgdGVyIHBhcmEgYWp1c3RhciBhcyBmdW7Dp8O1ZXMgbm9zIGRhZG9zIGVzdHJhdGlmaWNhZG9zLiBBY2hvIHF1ZSBmYXogZW0gYmxvY29zLiBWYWkgYXBsaWNhbmRvIG9zIG1lc21vcyBwYXLDom1ldHJvcyBwYXJhIHRvZG9zIG9zIGVzdHJhdG9zIGEgY2FkYSBtb2RlbG8uCgotIHBhcmEgY2FkYSBlc3RyYXRvIChlc3BhY2lhbCBvdSB0ZW1wb3JhbCkgdXNhciAtIGZ1bsOnw6NvIGRzIGRvIERpc3RhbmNlIChhcmd1bWVudG9zIGLDoXNpY29zOiB0cnVuY2F0aW9uOyBrZXksIGFkanVzdG1lbnQsIHNjYWxlLi4uIGVzdHVkYXIgYXJndW1lbnRvcyBwYXJhIHZlciBzZSBtYWlzIGFsZ3VtIGludGVyZXNzYSkKCiMjIyAqTW9kZWxvcyBwZWxhIGFib3JkYWdlbSBNQ0RTIOKAkyBkYWRvcyBnbG9iYWlzKgoKQXF1aSBuw6NvIGZheiBzZW50aWRvIGVzdHJhdGlmaWNhcgoKLSBmdW7Dp8OjbyBkcyBkbyBEaXN0YW5jZSAoYXJndW1lbnRvcyBiw6FzaWNvczogdHJ1bmNhdGlvbjsga2V5LCBhZGp1c3RtZW50LCBzY2FsZS4uLiBlc3R1ZGFyIGFyZ3VtZW50b3MgcGFyYSB2ZXIgc2UgbWFpcyBhbGd1bSBpbnRlcmVzc2EuLi4gcGFyYSBhcyBjb3ZhcmnDoXZlaXMgZW50cmEgbyBhcmd1bWVudG8gZm9ybXVsYSkKCkRpY2FzIGVtIE1pbGxlciBldCBhbC4gMjAxOSBzb2JyZSBjb3ZhcmnDoXZlaXMgKHZlciBhcnF1aXZvIG5vIGRyaXZlcikuCgojIyAqUEFSVEUgVkkg4oCTIEF2YWxpYW5kbyBvcyBtb2RlbG9zKgoKIyMjICpBanVzdGUgZG9zIG1vZGVsb3MgKgoKLSBmdW7Dp8OjbyBnb2ZfZHMgCgrigJMgcGFyYSBnZXJhciBRLVEgcGxvdHMgZSB0ZXN0ZXMgYXNzb2NpYWRvcwoKIyMjICpTZWxlY2lvbmFuZG8gbW9kZWxvcyAoQUlDKSAqCgrigJMgZnVuw6fDo28gc3VtbWFyaXplX2RzX21vZGVscwoKRElDQVMgRVhUUkFTIERFIE1JTExFUiBldCBhbC4gMjAxOQoKIyMgKlBBUlRFIFZJSSDigJMgUFJPRFVUTyBGSU5BTCoKCi0gQ29tbyBvcmdhbml6YXIKCi0gSW50ZXJhdGl2aWRhZGUKCiMgQ3JpYXIgZXhwcmVzc8O1ZXMgcmVhdGl2YXMKcmVhY3RpdmUoKQpldmVudFJlYWN0aXZlKCkKCm9ic2VydmUoKQpvYnNlcnZlRXZlbnQoKQoKcmVhY3RpdmVWYWwoKQpyZWFjdGl2ZVZhbHVlcygpCgppc29sYXRlKCkKCgotIGdlcmFyIG8gdGFsIGRvY3VtZW50byBhdXRvbWF0aXphZG8gY29udGVuZG8gdG9kbyBlc3NlIGZsdXhvIG1haXMgb3MgcmVzdWx0YWRvcyBkYXMgYW7DoWxpc2VzOwoKLSB0ZW50YXIgdHJhbnNmb3JtYXIgaXNzbyBudW0gZGFzaGJvYXJkL2FwbGljYXRpdm8gw7puaWNvIGludGVncmFuZG8gY2FkYSBldGFwYSBkZXNzYSBudW1hIGRhcyBhYmFzIGRvIGRhc2hib2FyZAoKLSBQYWNvdGUgdGFyZ2V0cyBzZXJpYSDDumx0aWw/CgojIEdsb3Nzw6FyaW8KCiAtIGBFZmZvcnRgIC0gZXh0ZW5zw6NvIHRvdGFsIHBlcmNvcnJpZGEgZW0gbWV0cm9zIG5vIGNvbmp1bnRvIGRlIGRhZG9zIHNlbGVjaW9kby4KIAogLSA=